package com.aso.common.eventbus.basebean;

import android.support.annotation.NonNull;
import android.text.TextUtils;


import com.itsdf07.alog.ALog;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

/**
 * @Description ：所有EventBus的post事件分发均需继承该BaseBean
 * 该类属性记录了当次EventBus的事件来源、处理事件、目标指向，确保维护者有序跟踪维护
 * @Author itsdf07
 * @Time 2017/8/23
 */
public class EventBusBaseBean {
    private final String TAG = this.getClass().getSimpleName();
    /**
     * EventBus 处理事件：没赋值时默认为-1，则每个extends于该基类的子类，都自己去处理需要执行的默认内容
     */
    private int currentEvent = -1;

    /**
     * 执行目标：由于EventBus 是类似广播的机制，所以任何有注册的地方均可接收，
     * 在new EventBusBaseBean的时候，设置该target，可以在接收消息的地方做过滤，避免没必要的执行
     */
    private List<HashMap<String, String>> targetList = new ArrayList<>();

    /**
     * 标记事件发出的位置
     */
    private String targetFromClass;

    public int getCurrentEvent() {
        return currentEvent;
    }

    public void setCurrentEvent(int currentEvent) {
        this.currentEvent = currentEvent;
    }

    /**
     * 设置EventBus事件的接收对象：传接收类的类名
     *
     * @param targetTo           事件指向类
     * @param targetToMethodName 事件执行方法
     */
    public void setTarget(@NonNull Class<?> targetFrom, @NonNull Class<?> targetTo, @NonNull String targetToMethodName) {
        //TODO 能否改成对参数限制不能传空？@NotNull，目前这样限制Ide不会报错
        if (targetTo == null) {
            return;
        }
        if (TextUtils.isEmpty(targetToMethodName)) {
            return;
        }
        if (null == targetList) {
            targetList = new ArrayList<>();
        }
        /**
         * 用类名称与方法名作为Key存储Target指向的原因为：
         * 可能有人会使用到一个指向需要执行多个方法，
         * 比如A.class中需要同时调用一个以上的EventBus接收方法，不这样处理，HashMap会被覆盖掉
         */
        String key = targetTo.getSimpleName() + ":" + targetToMethodName;
        HashMap<String, String> target = new HashMap<>();
        target.put(key, targetToMethodName);
        this.targetList.add(target);
        targetFromClass = targetFrom.getSimpleName() + ":" + getMethodName(targetFrom, 4);
        ALog.dTag(TAG, "targetTo = %s", key);
        ALog.dTag(TAG, "targetFromClass = %s", targetFromClass);
    }

    /**
     * 当前类是否为执行类
     *
     * @param target
     * @return
     */
    public boolean isTarget(Class<?> target) {
        if (target == null) {
            return false;
        }
        boolean isTarget = false;
        String methodName = getMethodName(target, 4);
        String key = target.getSimpleName() + ":" + methodName;
        ALog.dTag(TAG, "targetTo = %s", key);
        ALog.dTag(TAG, "targetFrom = %s", targetFromClass);
        for (HashMap<String, String> targetName : targetList) {
            if (targetName == null) {
                continue;
            }
            //如果当前执行的类和方法都是指定需要执行的目标，则返回true
            if (!TextUtils.isEmpty(targetName.get(key))//获取出来的方法名不能为空
                    && targetName.get(key).equals(methodName)) //
            {
                return true;
            }
        }
        return isTarget;
    }

    public String getTargetFromClass() {
        return targetFromClass;
    }

    /**
     * 获取当前执行的方法名
     * Fun --> isTarget--> getMethodName() --> getStackTrace() --> getThreadStackTrace()
     * s[4]    s[3]    s[2]                   s[1]                s[0]
     *
     * @param callingClass
     * @return
     */
    public String getMethodName(Class<?> callingClass, int count) {
        String className = callingClass.getSimpleName();
        StackTraceElement[] s = Thread.currentThread().getStackTrace();
        String methodName = s[count].getMethodName();
        ALog.dTag(TAG, "className = %s,methodName = %s", className, methodName);
        return methodName;
    }
}
